package com.eulog.client.blackJack;

import com.eulog.client.trump.TrumpCard;

public class BlackJackStrategy {
	//Static
	public static double basicProbabilityOfEachCard[] = new double[10];
	static {
		int index; 
		for(int i=2; i<12; i++) {
			index = getIndexOfCardByEvaluation(i);
			if(i==10) {
				basicProbabilityOfEachCard[index] = 4.0/13.0;
			}
			else {
				basicProbabilityOfEachCard[index] = 1.0/13.0;
			}
			
		}
	}
	
	public enum SD { H, S, P, D, X, R, Y} // Hit, Stand, Split, Double, DoubleStand, Surrender,SurrenderStand
	
	private static final SD strategy1[] = { // 4 decks, S17, DAS, No surrender, peek
	//Dealer	2		3		4		5		6		7		8		9		T		A	Player	
			SD.H,	SD.H,	SD.H,	SD.H,	SD.H,	SD.H,	SD.H,	SD.H,	SD.H,	SD.H,	//	7
			SD.H,	SD.H,	SD.H,	SD.H,	SD.H,	SD.H,	SD.H,	SD.H,	SD.H,	SD.H,	//	8
			SD.H,	SD.D,	SD.D,	SD.D,	SD.D,	SD.H,	SD.H,	SD.H,	SD.H,	SD.H,	//	9
			SD.D,	SD.D,	SD.D,	SD.D,	SD.D,	SD.D,	SD.D,	SD.D,	SD.H,	SD.H,	//	10
			SD.D,	SD.D,	SD.D,	SD.D,	SD.D,	SD.D,	SD.D,	SD.D,	SD.D,	SD.H,	//	11
			SD.H,	SD.H,	SD.S,	SD.S,	SD.S,	SD.H,	SD.H,	SD.H,	SD.H,	SD.H,	//	12
			SD.S,	SD.S,	SD.S,	SD.S,	SD.S,	SD.H,	SD.H,	SD.H,	SD.H,	SD.H,	//	13
			SD.S,	SD.S,	SD.S,	SD.S,	SD.S,	SD.H,	SD.H,	SD.H,	SD.H,	SD.H,	//	14
			SD.S,	SD.S,	SD.S,	SD.S,	SD.S,	SD.H,	SD.H,	SD.H,	SD.H,	SD.H,	//	15
			SD.S,	SD.S,	SD.S,	SD.S,	SD.S,	SD.H,	SD.H,	SD.H,	SD.H,	SD.H,	//	16
			SD.S,	SD.S,	SD.S,	SD.S,	SD.S,	SD.S,	SD.S,	SD.S,	SD.S,	SD.S,	//	17
			SD.H,	SD.H,	SD.H,	SD.D,	SD.D,	SD.H,	SD.H,	SD.H,	SD.H,	SD.H,	//	A2
			SD.H,	SD.H,	SD.H,	SD.D,	SD.D,	SD.H,	SD.H,	SD.H,	SD.H,	SD.H,	//	A3
			SD.H,	SD.H,	SD.D,	SD.D,	SD.D,	SD.H,	SD.H,	SD.H,	SD.H,	SD.H,	//	A4
			SD.H,	SD.H,	SD.D,	SD.D,	SD.D,	SD.H,	SD.H,	SD.H,	SD.H,	SD.H,	//	A5
			SD.H,	SD.D,	SD.D,	SD.D,	SD.D,	SD.H,	SD.H,	SD.H,	SD.H,	SD.H,	//	A6
			SD.S,	SD.X,	SD.X,	SD.X,	SD.X,	SD.S,	SD.S,	SD.H,	SD.H,	SD.H,	//	A7
			SD.S,	SD.S,	SD.S,	SD.S,	SD.S,	SD.S,	SD.S,	SD.S,	SD.S,	SD.S,	//	A8
			SD.S,	SD.S,	SD.S,	SD.S,	SD.S,	SD.S,	SD.S,	SD.S,	SD.S,	SD.S,	//	A9
			SD.P,	SD.P,	SD.P,	SD.P,	SD.P,	SD.P,	SD.H,	SD.H,	SD.H,	SD.H,	//	22
			SD.P,	SD.P,	SD.P,	SD.P,	SD.P,	SD.P,	SD.H,	SD.H,	SD.H,	SD.H,	//	33
			SD.H,	SD.H,	SD.H,	SD.P,	SD.P,	SD.H,	SD.H,	SD.H,	SD.H,	SD.H,	//	44
			SD.D,	SD.D,	SD.D,	SD.D,	SD.D,	SD.D,	SD.D,	SD.D,	SD.H,	SD.H,	//	55
			SD.P,	SD.P,	SD.P,	SD.P,	SD.P,	SD.H,	SD.H,	SD.H,	SD.H,	SD.H,	//	66
			SD.P,	SD.P,	SD.P,	SD.P,	SD.P,	SD.P,	SD.H,	SD.H,	SD.H,	SD.H,	//	77
			SD.P,	SD.P,	SD.P,	SD.P,	SD.P,	SD.P,	SD.P,	SD.P,	SD.P,	SD.P,	//	88
			SD.P,	SD.P,	SD.P,	SD.P,	SD.P,	SD.S,	SD.P,	SD.P,	SD.S,	SD.S,	//	99
			SD.S,	SD.S,	SD.S,	SD.S,	SD.S,	SD.S,	SD.S,	SD.S,	SD.S,	SD.S,	//	TT
			SD.P,	SD.P,	SD.P,	SD.P,	SD.P,	SD.P,	SD.P,	SD.P,	SD.P,	SD.P,	//	AA
	};
	
	public static final int indexOfStrategyNull = 0;
	public static final int indexOfStrategyHiOpt2 = 1;
	public static final int indexOfstrategyOmega2 = 2;
	public static final int indexOfstrategyZenCount = 3;
	public static final int indexOfstrategySimple = 4;
	
	private int strategyNull[] = {0,0,0,0,0,0,0,0,0,0};
	private int strategyHiOpt2[] = {1,1,2,2,1,1,0,0,-2,0};
	private int strategyZenCount[] = {1,1,2,2,2,1,0,0,-2,-1};
	private int strategyOmega2[] = {1,1,2,2,2,1,0,-1,-2,0};
	private int strategySimple[] = {1,1,1,1,1,1,0,-1,-1,-1};
	
	private final BlackJackDecks decks;
	private int cardStatistic[] = new int[10];
	private BlackJackRules rules;
	
	public BlackJackStrategy(BlackJackDecks d,BlackJackRules r) {
		decks = d;
		rules = r;
	}
	
	@Override
	public String toString() {
		String name = "";
		
		for(int i=0; i<10; i++) {
			name += cardStatistic[i] + " ";
			if(i==4) name+="| ";
		}
		
		name = "( " + name + " : " + decks.getID() + ", curr " + decks.getUsedCardsNumber() +" )";
		name += " H." + getCountingStrategy(strategyHiOpt2);
		name += " Z." + getCountingStrategy(strategyZenCount);
		name += " O." + getCountingStrategy(strategyOmega2);
		name += " S." + getCountingStrategy(strategySimple);
		
		return name;
	}
	
	public int[] getCardStatistic() {return cardStatistic;}
	
	public BlackJackRules getRules() {return rules;}
	
	public void countCard(TrumpCard c) {
		cardStatistic[getIndexOfCard(c)]++;
	}
	
	public static int getIndexOfCard(TrumpCard c) {
		int index = BlackJack.evaluateRank(c);
		return getIndexOfCardByEvaluation(index);
	}
	
	public static int getIndexOfCardByEvaluation(int evaluation) {
		return evaluation-2;
	}
	
	public int getCount(int pivotNum) {
		int count = 0;
		
		for(int i=0; i<10; i++) {
			if( (pivotNum-1) < i ) count--;
			else count++;
		}
		
		return count;
	}
	
	public BlackJackDecks getDecks() {return decks;}

	public SD getStrategy(TrumpCard dealerFaceCard,BlackJackHandCards playerCards) {
		if(playerCards.size()<2) return SD.H;
		
		int index = getStrategyIndex(dealerFaceCard, playerCards);
		
		// return -1 when hit, return -2 when stand, in all case of not listing in strategy table
		if(index == -1) return SD.H;
		if(index == -2) return SD.S;
		
		return strategy1[index];
	}
	
	public int getStrategyIndex(TrumpCard dealerFaceCard,BlackJackHandCards playerCards) {
		// return -1 when hit, return -2 when stand, in all case of not listing in strategy table
		int index = 0;
		index += getIndexOfCard(dealerFaceCard);
		
		if(playerCards.isTwoCardsSameRank() && playerCards.size() == 2) {
			index += (getIndexOfCard(playerCards.get(0))+19)*10;
			return index;
		}
		
		if(playerCards.hasAce()) {
			int evalWithoutAce = playerCards.calculateRanksWithoutOneAceAndOtherAceIsOneValue();
			if(evalWithoutAce<10) {
				index += (getIndexOfCardByEvaluation(evalWithoutAce)+11) * 10;
				return index;
			}
		}

		// regular case;
		int eval = playerCards.calculateRanks();
		if(eval < 7) return -1;
		if (eval > 17) return -2;
		
		index += (eval-7)*10;
		
		return index;
	}
	
	public int getCountingStrategy(int countingStrategy[]) {
		int value = 0;
		for(int i=0; i<10; i++) {
			value += cardStatistic[i] * countingStrategy[i];
		}
		return value;
	}
	
	public int[] getCountingStarategyByIndex(int strategyIndex) {
		if(strategyIndex==indexOfStrategyHiOpt2) return strategyHiOpt2;
		else if(strategyIndex==indexOfstrategyOmega2) return strategyOmega2;
		else if(strategyIndex==indexOfstrategyZenCount) return strategyZenCount;
		else if(strategyIndex==indexOfstrategySimple) return strategySimple;
		
		return strategyNull;
	
	}
	
	public double isDecksPositiveForPlayer(int strategyIndex) {
		int counting = getCountingStrategy(getCountingStarategyByIndex(strategyIndex));
		
		return counting / (decks.getDeckSize() - (decks.getUsedCardsNumber()/52));
	}
	
}
